package cn.classg.redisson.factory;

import cn.classg.redisson.constants.LockConstant;
import cn.classg.redisson.properties.LockConfigProperties;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.redisson.config.*;
import org.redisson.connection.balancer.LoadBalancer;
import org.redisson.connection.balancer.RandomLoadBalancer;
import org.redisson.connection.balancer.RoundRobinLoadBalancer;
import org.redisson.connection.balancer.WeightedRoundRobinBalancer;
import org.springframework.util.Assert;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 初始化配置工厂
 * @author CLASSG
 */
public class ServerConfigInitFactory {

    /**
     * 初始化单机模式参数
     *
     * @param singleServerConfig 单机模式配置
     */
    @SneakyThrows
    public static void initSingleConfig(SingleServerConfig singleServerConfig,
                                        LockConfigProperties lockConfig) throws URISyntaxException {
        // 获取配置文件中单机模式的配置信息
        LockConfigProperties.SingleConfig singleConfig = lockConfig.getSingleServer();
        // 设置Redis单机服务器连接地址  eg: redis://127.0.0.1:6739
        singleServerConfig.setAddress(String.format("%s%s%s%s", LockConstant.REDIS_URL_PREFIX,
                singleConfig.getAddress(), LockConstant.COLON, singleConfig.getPort()));
        // 设置客户端名称
        singleServerConfig.setClientName(lockConfig.getClientName());
        // 设置最小空闲连接数
        singleServerConfig.setConnectionMinimumIdleSize(singleConfig.getConnMinIdleSize());
        // 设置连接池大小
        singleServerConfig.setConnectionPoolSize(singleConfig.getConnPoolSize());
        // 设置同任何节点建立连接时的等待超时，单位：毫秒
        singleServerConfig.setConnectTimeout(singleConfig.getConnTimeout());
        // 设置使用的是几号库（数据库编号），默认使用0号库
        singleServerConfig.setDatabase(singleConfig.getDatabase());
        // 设置DNS监测时间间隔，单位：毫秒，该配置需要dnsMonitoring设为true
        singleServerConfig.setDnsMonitoringInterval(singleConfig.getDnsMonitoringInterval());
        // 如果当前连接池里的连接数量超过了最小空闲连接数，而同时有连接空闲时间超过了该数值，
        // 那么这些连接将会自动被关闭，并从连接池里去掉。单位：毫秒
        singleServerConfig.setIdleConnectionTimeout(singleConfig.getIdleConnTimeout());
        singleServerConfig.setKeepAlive(singleConfig.isKeepAlive());
        // 设置Redis服务连接密码
        if (StringUtils.isNotBlank(singleConfig.getPassword())) {
            singleServerConfig.setPassword(singleConfig.getPassword());
        }
        // 设置命令失败重试次数 如果尝试达到 retryAttempts（命令失败重试次数） 仍然不能将命令发送至某个指定的节点时，将抛出错误。
        // 如果尝试在此限制之内发送成功，则开始启用 timeout（命令等待超时） 计时。默认为3次
        singleServerConfig.setRetryAttempts(singleConfig.getRetryAttempts());
        // 命令重试发送时间间隔，单位：毫秒
        singleServerConfig.setRetryInterval(singleConfig.getRetryInterval());
        // 设置是否启用SSL终端识别(安全性)
        singleServerConfig.setSslEnableEndpointIdentification(lockConfig.isSslEnableEndpointIdentification());
        if (lockConfig.getSslKeystore() != null) {
            // 设置SSL钥匙库路径
            singleServerConfig.setSslKeystore(new URI(lockConfig.getSslKeystore()).toURL());
        }
        if (lockConfig.getSslKeystorePassword() != null) {
            // 设置SSL钥匙库密码
            singleServerConfig.setSslKeystorePassword(lockConfig.getSslKeystorePassword());
        }
        // 设置SSL实现方式，确定采用哪种方式（JDK或OPENSSL）来实现SSL连接。默认JDK
        singleServerConfig
                .setSslProvider(LockConstant.JDK.equalsIgnoreCase(lockConfig.getSslProvider()) ? SslProvider.JDK
                        : SslProvider.OPENSSL);
    }

    /**
     * 初始化主从模式参数
     *
     * @param masterSlaveServersConfig 主从模式配置
     * @throws URISyntaxException URISyntaxException
     */
    public static void initMasterSlaveConfig(MasterSlaveServersConfig masterSlaveServersConfig,
                                             LockConfigProperties lockConfig) throws URISyntaxException, MalformedURLException {
        LockConfigProperties.MasterSlaveConfig masterSlaveConfig = lockConfig.getMasterSlaveServer();
        // 设置主节点地址，可以通过host:port的格式来指定主节点地址
        masterSlaveServersConfig.setMasterAddress(
                String.format("%s%s", LockConstant.REDIS_URL_PREFIX, masterSlaveConfig.getMasterAddress()));
        // 从节点地址
        String[] addressArr = masterSlaveConfig.getSlaveAddresses().split(LockConstant.COMMA);
        // 添加从节点地址（可能是多个从节点）
        Arrays.asList(addressArr).forEach(address ->
                masterSlaveServersConfig.addSlaveAddress(String.format("%s%s", LockConstant.REDIS_URL_PREFIX, address)));

        // 根据用户配置，获取读取操作的负载均衡模式类型获取读取模式（比如：从slave读，从master读，从master和slave一起读）
        ReadMode readMode = getReadMode(masterSlaveConfig.getReadMode());
        Assert.notNull(readMode, "Unknown load balancing mode type for read operations");
        // 设置读取操作的负载均衡模式（比如：从slave读，或master读）
        masterSlaveServersConfig.setReadMode(readMode);

        // 根据用户配置，获取订阅模型（在master节点上订阅还是在slave节点上订阅）
        SubscriptionMode subscriptionMode = getSubscriptionMode(masterSlaveConfig.getSubMode());
        Assert.notNull(subscriptionMode, "The type of load balancing pattern for an unknown subscription operation");
        masterSlaveServersConfig.setSubscriptionMode(subscriptionMode);

        //根据用户配置，获取负载均衡的轮询算法
        LoadBalancer loadBalancer = getLoadBalancer(masterSlaveConfig.getLoadBalancer(),
                masterSlaveConfig.getWeightMaps(), masterSlaveConfig.getDefaultWeight());
        Assert.notNull(loadBalancer, "Unknown type of load balancing algorithm");
        // 设置负载均衡的轮询算法
        masterSlaveServersConfig.setLoadBalancer(loadBalancer);

        // 设置锁使用的库
        masterSlaveServersConfig.setDatabase(masterSlaveConfig.getDatabase());
        // 设置slave连接池的大小（在redisson初始化的时候会建立到master和slave的连接池以及发布订阅的连接池）
        masterSlaveServersConfig.setSlaveConnectionPoolSize(masterSlaveConfig.getSlaveConnectionPoolSize());
        // 设置master连接池大小
        masterSlaveServersConfig.setMasterConnectionPoolSize(masterSlaveConfig.getMasterConnectionPoolSize());
        // 设置发布订阅连接池的大小
        masterSlaveServersConfig.setSubscriptionConnectionPoolSize(masterSlaveConfig.getSubscriptionConnectionPoolSize());
        // 设置从节点连接池中最小空闲连接数
        masterSlaveServersConfig.setSlaveConnectionMinimumIdleSize(masterSlaveConfig.getSlaveConnectionMinimumIdleSize());
        // 设置主节点连接池中最小空闲连接数
        masterSlaveServersConfig.setMasterConnectionMinimumIdleSize(masterSlaveConfig.getMasterConnectionMinimumIdleSize());
        // 设置从节点发布和订阅连接池中的最小空闲连接数
        masterSlaveServersConfig.setSubscriptionConnectionMinimumIdleSize(masterSlaveConfig.getSubscriptionConnectionMinimumIdleSize());
        // 设置DNS监控间隔
        masterSlaveServersConfig.setDnsMonitoringInterval(masterSlaveConfig.getDnsMonitoringInterval());
        // 设置单个连接最大订阅数量
        masterSlaveServersConfig.setSubscriptionsPerConnection(masterSlaveConfig.getSubscriptionsPerConnection());
        if (StringUtils.isNotBlank(masterSlaveConfig.getPassword())) {
            masterSlaveServersConfig.setPassword(masterSlaveConfig.getPassword());
        }
        // 设置命令失败重试次数
        masterSlaveServersConfig.setRetryAttempts(masterSlaveConfig.getRetryAttempts());
        // 设置命令重试发送时间间隔，单位：毫秒
        masterSlaveServersConfig.setRetryInterval(masterSlaveConfig.getRetryInterval());
        // 设置命令等待超时，单位：毫秒
        masterSlaveServersConfig.setTimeout(masterSlaveConfig.getTimeout());
        // 设置连接超时，单位：毫秒
        masterSlaveServersConfig.setConnectTimeout(masterSlaveConfig.getConnectTimeout());
        // 设置连接空闲超时，单位：毫秒
        masterSlaveServersConfig.setIdleConnectionTimeout(masterSlaveConfig.getIdleConnectionTimeout());
        // 根据用户配置，设置ssl配置
        setLockSslConfigAndClientName(masterSlaveServersConfig, lockConfig);
    }

    /**
     * 初始化集群模式参数
     *
     * @param clusterServerConfig 集群模式配置
     */
    public static void initClusterConfig(ClusterServersConfig clusterServerConfig, LockConfigProperties lockConfig) {
        // 获取配置文件中集群相关配置
        LockConfigProperties.ClusterConfig clusterConfig = lockConfig.getClusterServer();
        // 按逗号解析配置文件中的集群地址，cluster方式至少6个节点(3主3从，3主做sharding，3从用来保证主宕机后可以高可用)
        String[] addressArr = clusterConfig.getNodeAddresses().split(LockConstant.COMMA);
        Arrays.asList(addressArr).forEach(address -> clusterServerConfig
                .addNodeAddress(String.format("%s%s", LockConstant.REDIS_URL_PREFIX, address)));
        // 设置集群扫描间隔时间（单位是毫秒）
        clusterServerConfig.setScanInterval(clusterConfig.getScanInterval());

        // 设置读取操作模式（是从slave读还是master读还是slave和master上都可以读）
        ReadMode readMode = getReadMode(clusterConfig.getReadMode());
        Assert.notNull(readMode, "Unknown load balancing mode type for read operations");
        clusterServerConfig.setReadMode(readMode);

        // 获取消息订阅模式，当客户端需要订阅channel的时候需要知道是取master上订阅还是slave上订阅
        SubscriptionMode subscriptionMode = getSubscriptionMode(clusterConfig.getSubMode());
        Assert.notNull(subscriptionMode, "The type of load balancing pattern for an unknown subscription operation");
        clusterServerConfig.setSubscriptionMode(subscriptionMode);

        // 设置根据用户的配置类型设置对应的负载均衡算法
        LoadBalancer loadBalancer = getLoadBalancer(clusterConfig.getLoadBalancer(), clusterConfig.getWeightMaps(),
                clusterConfig.getDefaultWeight());
        Assert.notNull(loadBalancer, "Unknown type of load balancing algorithm");
        clusterServerConfig.setLoadBalancer(loadBalancer);

        // 设置节点发布和订阅连接池的最小空闲连接数
        clusterServerConfig.setSubscriptionConnectionMinimumIdleSize(clusterConfig.getSubConnMinIdleSize());
        // 设置节点发布和订阅连接池的连接数量
        clusterServerConfig.setSubscriptionConnectionPoolSize(clusterConfig.getSubConnPoolSize());
        // 设置从节点连接池的最小空闲连接数量
        clusterServerConfig.setSlaveConnectionMinimumIdleSize(clusterConfig.getSlaveConnMinIdleSize());
        // 设置从节点连接池的连接数量
        clusterServerConfig.setSlaveConnectionPoolSize(clusterConfig.getSlaveConnPoolSize());
        // 设置主节点连接池的最小空闲连接数量
        clusterServerConfig.setMasterConnectionMinimumIdleSize(clusterConfig.getMasterConnMinIdleSize());
        // 设置主节点连接池的连接数量
        clusterServerConfig.setMasterConnectionPoolSize(clusterConfig.getMasterConnPoolSize());
        // 连接空闲超时，单位：毫秒。如果当前连接池里的连接数量超过了最小空闲连接数，而同时有连接空闲时间超过了该数值，
        // 那么这些连接将会自动被关闭，并从连接池里去掉
        clusterServerConfig.setIdleConnectionTimeout(clusterConfig.getIdleConnTimeout());
        // 同任何节点建立连接时的等待超时。时间单位是毫秒。
        clusterServerConfig.setConnectTimeout(clusterConfig.getConnTimeout());
        // 等待节点回复命令的时间。该时间从命令发送成功时开始计时
        clusterServerConfig.setTimeout(clusterConfig.getTimeout());
        // 设置命令失败重试次数
        clusterServerConfig.setRetryAttempts(clusterConfig.getRetryAttempts());
        // 设置命令重试发送时间间隔，单位：毫秒
        clusterServerConfig.setRetryInterval(clusterConfig.getRetryInterval());
        // 设置连接Redis的密码
        if (StringUtils.isNotBlank(clusterConfig.getPassword())) {
            clusterServerConfig.setPassword(clusterConfig.getPassword());
        }
        // 设置单个连接最大订阅数量
        clusterServerConfig.setSubscriptionsPerConnection(clusterConfig.getSubPerConn());
        // 设置客户端名称
        clusterServerConfig.setClientName(lockConfig.getClientName());
    }

    /**
     * 初始化云托管模式参数
     *
     * @param replicatedServersConfig 云托管模式配置
     * @throws URISyntaxException URISyntaxException
     */
    public static void initReplicatedServersConfig(ReplicatedServersConfig replicatedServersConfig,
                                                   LockConfigProperties lockConfig) throws URISyntaxException, MalformedURLException {
        // 获取到云托管模式的配置参数
        LockConfigProperties.ReplicatedConfig replicatedConfig = lockConfig.getReplicatedServer();

        // 拆分并组装redis节点的地址，eg: redis://127.0.0.1:6379
        String[] addressArr = replicatedConfig.getNodeAddresses().split(LockConstant.COMMA);
        Arrays.asList(addressArr).forEach(address -> replicatedServersConfig
                .addNodeAddress(String.format("%s%s", LockConstant.REDIS_URL_PREFIX, address)));
        // 根据用户配置的读取模式决定读操作从哪类节点上读取（比如slave、master等）
        ReadMode readMode = getReadMode(replicatedConfig.getReadMode());
        Assert.notNull(readMode, "Unknown load balancing mode type for read operations");
        replicatedServersConfig.setReadMode(readMode);

        // 根据用户配置的订阅模式决定发起订阅时是向那种类型的节点订阅（slave、master）
        SubscriptionMode subscriptionMode = getSubscriptionMode(replicatedConfig.getSubscriptionMode());
        Assert.notNull(subscriptionMode, "The type of load balancing pattern for an unknown subscription operation");
        replicatedServersConfig.setSubscriptionMode(subscriptionMode);

        // 设置负载均衡策略
        LoadBalancer loadBalancer = getLoadBalancer(replicatedConfig.getLoadBalancer(),
                replicatedConfig.getWeightMaps(), replicatedConfig.getDefaultWeight());
        Assert.notNull(loadBalancer, "Unknown type of load balancing algorithm");
        replicatedServersConfig.setLoadBalancer(loadBalancer);

        // 设置集群扫描间隔时间（单位是毫秒）
        replicatedServersConfig.setScanInterval(replicatedConfig.getScanInterval());
        // 设置锁使用的库
        replicatedServersConfig.setDatabase(replicatedConfig.getDatabase());
        // 设置从节点连接池的连接数量
        replicatedServersConfig.setSlaveConnectionPoolSize(replicatedConfig.getSlaveConnectionPoolSize());
        // 设置主节点连接池的连接数量
        replicatedServersConfig.setMasterConnectionPoolSize(replicatedConfig.getMasterConnectionPoolSize());
        // 设置节点发布和订阅连接池的连接数量
        replicatedServersConfig.setSubscriptionConnectionPoolSize(replicatedConfig.getSubscriptionConnectionPoolSize());
        // 设置从节点连接池的最小空闲连接数量
        replicatedServersConfig.setSlaveConnectionMinimumIdleSize(replicatedConfig.getSlaveConnectionMinimumIdleSize());
        // 设置主节点连接池的最小空闲连接数量
        replicatedServersConfig.setMasterConnectionMinimumIdleSize(replicatedConfig.getMasterConnectionMinimumIdleSize());
        // 设置节点发布和订阅连接池的最小空闲连接数
        replicatedServersConfig.setSubscriptionConnectionMinimumIdleSize(replicatedConfig.getSubscriptionConnectionMinimumIdleSize());
        // 设置DNS监控间隔
        replicatedServersConfig.setDnsMonitoringInterval(replicatedConfig.getDnsMonitoringInterval());
        // 设置单个连接最大订阅数量
        replicatedServersConfig.setSubscriptionsPerConnection(replicatedConfig.getSubscriptionsPerConnection());
        if (StringUtils.isNotBlank(replicatedConfig.getPassword())) {
            replicatedServersConfig.setPassword(replicatedConfig.getPassword());
        }
        // 设置命令失败重试次数
        replicatedServersConfig.setRetryAttempts(replicatedConfig.getRetryAttempts());
        // 设置命令重试发送时间间隔，单位：毫秒
        replicatedServersConfig.setRetryInterval(replicatedConfig.getRetryInterval());
        // 等待节点回复命令的时间。该时间从命令发送成功时开始计时
        replicatedServersConfig.setTimeout(replicatedConfig.getTimeout());
        // 同任何节点建立连接时的等待超时。时间单位是毫秒。
        replicatedServersConfig.setConnectTimeout(replicatedConfig.getConnectTimeout());
        // 连接空闲超时，单位：毫秒。如果当前连接池里的连接数量超过了最小空闲连接数，而同时有连接空闲时间超过了该数值，
        // 那么这些连接将会自动被关闭，并从连接池里去掉
        replicatedServersConfig.setIdleConnectionTimeout(replicatedConfig.getIdleConnectionTimeout());
        // 根据用户配置，设置ssl配置
        setLockSslConfigAndClientName(replicatedServersConfig, lockConfig);
    }

    /**
     * 初始化哨兵模式参数
     *
     * @param sentinelServersConfig 哨兵模式配置
     * @throws URISyntaxException URISyntaxException
     */
    public static void initSentinelServersConfig(SentinelServersConfig sentinelServersConfig,
                                                 LockConfigProperties lockConfig) throws URISyntaxException, MalformedURLException {
        // 获取配置文件中用户指定的哨兵配置
        LockConfigProperties.SentinelConfig sentinelConfig = lockConfig.getSentinelServer();
        // 拆分并组装redis节点的地址，eg: redis://127.0.0.1:6379
        String[] addressArr = sentinelConfig.getSentinelAddresses().split(LockConstant.COMMA);
        Arrays.asList(addressArr).forEach(address -> sentinelServersConfig
                .addSentinelAddress(String.format("%s%s", LockConstant.REDIS_URL_PREFIX, address)));

        // 根据用户配置的读取模式决定读操作从哪类节点上读取（比如slave、master等）
        ReadMode readMode = getReadMode(sentinelConfig.getReadMode());
        Assert.notNull(readMode, "Unknown load balancing mode type for read operations");
        sentinelServersConfig.setReadMode(readMode);

        // 根据用户配置的订阅模式决定发起订阅时是向那种类型的节点订阅（slave、master）
        SubscriptionMode subscriptionMode = getSubscriptionMode(sentinelConfig.getSubMode());
        Assert.notNull(subscriptionMode, "The type of load balancing pattern for an unknown subscription operation");
        sentinelServersConfig.setSubscriptionMode(subscriptionMode);

        // 设置负载均衡策略
        LoadBalancer loadBalancer = getLoadBalancer(sentinelConfig.getLoadBalancer(), sentinelConfig.getWeightMaps(),
                sentinelConfig.getDefaultWeight());
        Assert.notNull(loadBalancer, "Unknown type of load balancing algorithm");
        sentinelServersConfig.setLoadBalancer(loadBalancer);

        // 设置主节点名称
        sentinelServersConfig.setMasterName(sentinelConfig.getMasterName());
        // 设置锁使用的库
        sentinelServersConfig.setDatabase(sentinelConfig.getDatabase());
        // 设置从节点连接池的连接数量
        sentinelServersConfig.setSlaveConnectionPoolSize(sentinelConfig.getSlaveConnectionPoolSize());
        // 设置主节点连接池的连接数量
        sentinelServersConfig.setMasterConnectionPoolSize(sentinelConfig.getMasterConnectionPoolSize());
        // 设置节点发布和订阅连接池的连接数量
        sentinelServersConfig.setSubscriptionConnectionPoolSize(sentinelConfig.getSubscriptionConnectionPoolSize());
        // 设置从节点连接池的最小空闲连接数量
        sentinelServersConfig.setSlaveConnectionMinimumIdleSize(sentinelConfig.getSlaveConnectionMinimumIdleSize());
        // 设置主节点连接池的最小空闲连接数量
        sentinelServersConfig.setMasterConnectionMinimumIdleSize(sentinelConfig.getMasterConnectionMinimumIdleSize());
        // 设置节点发布和订阅连接池的最小空闲连接数
        sentinelServersConfig.setSubscriptionConnectionMinimumIdleSize(sentinelConfig.getSubscriptionConnectionMinimumIdleSize());
        // 设置DNS监控间隔
        sentinelServersConfig.setDnsMonitoringInterval(sentinelConfig.getDnsMonitoringInterval());
        // 设置单个连接最大订阅数量
        sentinelServersConfig.setSubscriptionsPerConnection(sentinelConfig.getSubscriptionsPerConnection());
        if (StringUtils.isNotBlank(sentinelConfig.getPassword())) {
            sentinelServersConfig.setPassword(sentinelConfig.getPassword());
        }
        // 设置命令失败重试次数
        sentinelServersConfig.setRetryAttempts(sentinelConfig.getRetryAttempts());
        // 设置命令重试发送时间间隔，单位：毫秒
        sentinelServersConfig.setRetryInterval(sentinelConfig.getRetryInterval());
        // 等待节点回复命令的时间。该时间从命令发送成功时开始计时
        sentinelServersConfig.setTimeout(sentinelConfig.getTimeout());
        // 同任何节点建立连接时的等待超时。时间单位是毫秒。
        sentinelServersConfig.setConnectTimeout(sentinelConfig.getConnectTimeout());
        // 连接空闲超时，单位：毫秒。如果当前连接池里的连接数量超过了最小空闲连接数，而同时有连接空闲时间超过了该数值，
        // 那么这些连接将会自动被关闭，并从连接池里去掉
        sentinelServersConfig.setIdleConnectionTimeout(sentinelConfig.getIdleConnectionTimeout());
        // 根据用户配置，设置ssl配置
        setLockSslConfigAndClientName(sentinelServersConfig, lockConfig);
    }

    /**
     * 根据readModeType返回ReadMode
     *
     * @param readModeType 读取操作的负载均衡模式类型
     * @return ReadMode OR NULL
     */
    private static ReadMode getReadMode(String readModeType) {
        if (LockConstant.SubReadMode.SLAVE.equals(readModeType)) {
            // 从slave上读
            return ReadMode.SLAVE;
        }
        if (LockConstant.SubReadMode.MASTER.equals(readModeType)) {
            // 从master上读
            return ReadMode.MASTER;
        }
        if (LockConstant.SubReadMode.MASTER_SLAVE.equals(readModeType)) {
            // 从master和slave上读
            return ReadMode.MASTER_SLAVE;
        }
        return null;
    }

    /**
     * 根据subscriptionModeType返回SubscriptionMode
     *
     * @param subscriptionModeType 订阅操作的负载均衡模式类型
     * @return SubscriptionMode OR NULL
     */
    private static SubscriptionMode getSubscriptionMode(String subscriptionModeType) {
        if (LockConstant.SubReadMode.SLAVE.equals(subscriptionModeType)) {
            // 订阅的时候从slave上订阅
            return SubscriptionMode.SLAVE;
        }
        if (LockConstant.SubReadMode.MASTER.equals(subscriptionModeType)) {
            // 订阅的时候从master上订阅
            return SubscriptionMode.MASTER;
        }
        return null;
    }

    /**
     * 根据用户的配置类型设置对应的LoadBalancer
     *
     * @param loadBalancerType   负载均衡算法类名
     * @param customerWeightMaps 权重值设置，当负载均衡算法是权重轮询调度算法时该属性有效
     * @param defaultWeight      默认权重值，当负载均衡算法是权重轮询调度算法时该属性有效
     * @return LoadBalancer OR NULL
     */
    private static LoadBalancer getLoadBalancer(String loadBalancerType, String customerWeightMaps, int defaultWeight) {
        // 随机调度算法
        if (LockConstant.LoadBalancer.RANDOM_LOAD_BALANCER.equals(loadBalancerType)) {
            return new RandomLoadBalancer();
        }
        // 轮询调度算法
        if (LockConstant.LoadBalancer.ROUND_ROBIN_LOAD_BALANCER.equals(loadBalancerType)) {
            return new RoundRobinLoadBalancer();
        }
        // 权重调度算法
        if (LockConstant.LoadBalancer.WEIGHTED_ROUND_ROBIN_BALANCER.equals(loadBalancerType)) {
            Map<String, Integer> weights = new HashMap<>(16);
            String[] weightMaps = customerWeightMaps.split(LockConstant.SEMICOLON);
            Arrays.asList(weightMaps)
                    .forEach(weightMap -> weights.put(
                            LockConstant.REDIS_URL_PREFIX + weightMap.split(LockConstant.COMMA)[0],
                            Integer.parseInt(weightMap.split(LockConstant.COMMA)[1])));
            return new WeightedRoundRobinBalancer(weights, defaultWeight);
        }
        return null;
    }

    /**
     * 设置SSL配置
     *
     * @param lockAutoConfig lockAutoConfig
     * @param <T>            lockAutoConfig
     * @throws URISyntaxException URISyntaxException
     */
    private static <T extends BaseMasterSlaveServersConfig> void setLockSslConfigAndClientName(T lockAutoConfig,
                                                                                               LockConfigProperties lockConfig)
            throws URISyntaxException, MalformedURLException {
        if (lockConfig.isSslEnableEndpointIdentification()) {
            lockAutoConfig.setClientName(lockConfig.getClientName());
            lockAutoConfig.setSslEnableEndpointIdentification(lockConfig.isSslEnableEndpointIdentification());
            if (lockConfig.getSslKeystore() != null) {
                lockAutoConfig.setSslKeystore(new URI(lockConfig.getSslKeystore()).toURL());
            }
            if (lockConfig.getSslKeystorePassword() != null) {
                lockAutoConfig.setSslKeystorePassword(lockConfig.getSslKeystorePassword());
            }
            if (lockConfig.getSslTruststore() != null) {
                lockAutoConfig.setSslTruststore(new URI(lockConfig.getSslTruststore()).toURL());
            }
            if (lockConfig.getSslTruststorePassword() != null) {
                lockAutoConfig.setSslTruststorePassword(lockConfig.getSslTruststorePassword());
            }
            lockAutoConfig.setSslProvider(LockConstant.JDK.equalsIgnoreCase(lockConfig.getSslProvider()) ? SslProvider.JDK
                    : SslProvider.OPENSSL);
        }
    }

}
